package delegate;

import interfaces.ServerInterface;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;

import java.util.List;
import java.util.Map;

import started.ReadProperties;
import Implementation.Intervalos;
import Implementation.ServerImpl;
import genericServer.server.GenericConsumer;
import genericServer.server.GenericResource;
import entility.Job;
import entility.JobImpl;
import entility.Machine;
import entility.Notification;
import entility.Range;

public class MethodServer<S extends Socket> extends GenericConsumer<S> {
	// create any constructor type
	public MethodServer(GenericResource<S> re) {


		super(re);


	}





	@Override
	protected void doSomething(S str) {
		try {
			// TODO Auto-generated method stub
			ObjectInputStream in = new ObjectInputStream(str.getInputStream());
			Job msg = (JobImpl) in.readObject();

			ReadProperties props = new ReadProperties();
			ServerInterface server = ServerImpl.getInstance(props.getThisServer());

			System.out.println("Log\nMethod: " + msg.getMethod());
			System.out.println("Data: " + msg.getData());
			

			switch (msg.getMethod()) {
			
			
			case "amostragemConcluida":{

				
				Job output = new JobImpl(Notification.SERVER);
				output.setData("Ok");
				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());;
				out.writeObject(output);
				out.flush();
				out.close();
				in.close();


				Machine host = new ArrayList<Machine>(msg.getRangeMap().keySet()).get(0);
				ServerImpl.amostragemConcluida.put(host.ip, true);
				ServerImpl.intervalos.put(host, msg.getRangeMap().get(host));

				boolean y = true;
				for(boolean x: ServerImpl.amostragemConcluida.values()){

					if(!x){
						y = false;
					}
				}

				if(y){



					long min = -2147483600;
					long max = 2147483600;

					
					Intervalos intervals= new Intervalos(ServerImpl.intervalos);

					intervals.uniqueInterval();
					intervals.validade(min, max);

					Map<Machine, List<Range> > listaIntervalos = intervals.toMap();
					
			
					
					
					for(Machine maquina: ServerImpl.listHosts){

						Job job = new JobImpl(Notification.SERVER);

						job.setData(listaIntervalos);
						job.setMethod("sort");



						try{
							System.out.println("Send to Host");
							maquina.getMessage(job);


						}catch(Exception e){

							e.printStackTrace();

						}

					}


				}

				break;
			}
			case "getServers": {
				ObjectOutputStream out = new ObjectOutputStream(
						str.getOutputStream());

				List<Machine> serversMachine = ServerImpl.listServers;
				List<String> servers = new ArrayList<String>();
				Job output = new JobImpl(Notification.SERVER);
				output.setMethod("response" + "\n");
				for (Machine serverMachine : serversMachine) {
					servers.add(serverMachine.ip + ":" + serverMachine.port);
				}
				System.out.println("Response: :"+servers + "\n");
				output.setData(servers);
				out.writeObject(output);
				out.flush();
				out.close();
				in.close();
				break;
			}

			case "getHosts": {
				ObjectOutputStream out = new ObjectOutputStream(		str.getOutputStream());
				List<Machine> hostsMachine = ServerImpl.listHosts;
				List<String> hosts = new ArrayList<String>();
				Job output = new JobImpl(Notification.SERVER);
				output.setMethod("response");
				for (Machine hostMachine : hostsMachine) {
					hosts.add(hostMachine.ip + ":" + hostMachine.port);
				}

				System.out.println("Response: "+ hosts + "\n");
				output.setData(hosts);
				out.writeObject(output);
				out.flush();
				out.close();
				in.close();
				break;

			}

			case "removeHost": {

				if( msg.getOrigin().equals(Notification.SERVER))
				{	
					in.close();
					break;
				}
				ObjectOutputStream out = new ObjectOutputStream( str.getOutputStream());
				List<String> data = msg.getData();
				String[] dataHost = data.get(0).split(":");
				String ip = dataHost[0];
				String port = dataHost[1];
				server.remove(new Machine(ip, Integer.parseInt(port)));

				out.writeObject(msg);
				out.flush();
				out.close();
				in.close();
				break;

			}

			case "removeServer": {
				ObjectOutputStream out = new ObjectOutputStream( str.getOutputStream());
				List<String> data = msg.getData();
				String[] dataHost = data.get(0).split(":");
				String ip = dataHost[0];
				String port = dataHost[1];
				server.removeServer(new Machine(ip, Integer.parseInt(port)));
				System.out.println("Response: ok\n");
				out.writeObject(msg);
				out.flush();
				out.close();
				in.close();
				break;

			}

			case "addHost": {

				if( msg.getOrigin().equals(Notification.SERVER))
				{	in.close();
				break;
				}

				ObjectOutputStream out = new ObjectOutputStream(	str.getOutputStream());
				List<String> data = msg.getData();
				String[] dataHost = data.get(0).split(":");
				String ip = dataHost[0];
				String port = dataHost[1];
				server.addHost(new Machine(ip, Integer.parseInt(port)));
				System.out.println("Response: ok\n");
				out.writeObject(msg);
				out.flush();
				out.close();
				in.close();
				break;
			}

			case "addServer": {
				ObjectOutputStream out = new ObjectOutputStream(	str.getOutputStream());
				List<String> data = msg.getData();
				String[] dataHost = data.get(0).split(":");
				String ip = dataHost[0];
				String port = dataHost[1];
				server.addServer(new Machine(ip, Integer.parseInt(port)));
				System.out.println("Response: ok\n");
				out.writeObject(msg);
				out.flush();
				out.close();
				in.close();
				break;
			}

			case "notify": {
				ObjectOutputStream out = new ObjectOutputStream(
						str.getOutputStream());

				Notification notification = new Notification(msg.getData());
				server.notify(notification);
				System.out.println("Response: ok\n");
				Job response = new JobImpl(Notification.SERVER);
				response.setData("OK");
				out.writeObject(response);
				out.flush();
				out.close();
				in.close();
				break;
			}


			case "quantityOfJobs": {

				System.out.println(msg.getOrigin());
				if( msg.getOrigin().equals(Notification.SERVER))
				{	in.close();
				break;
				}


				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
				server.updateQuatityOfJobs(msg);
				Job response = new JobImpl(Notification.SERVER);
				response.setData("OK");
				out.writeObject(response);
				out.flush();
				out.close();
				in.close();
				break;
			}

			case "getHostsAndJobs": {
				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
				Map<String , Integer > JobsAndHosts = ServerImpl.hostsAndJobs;
				Job response = new JobImpl(Notification.SERVER);
				List<String > jobs = new ArrayList<String>();

				for(String x: JobsAndHosts.keySet())
					jobs.add(x +":" +JobsAndHosts.get(x) );

				response.setData(jobs);
				out.writeObject(response);
				out.flush();
				out.close();
				in.close();
				break;
			}

			}

			str.close();

		} catch (Exception e) {
			e.printStackTrace();

		}

	}

}
